package com.happle.gcmclient.backendmanager;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Random;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONObject;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.happle.gcmclient.config.CommonUtilities;
import com.happle.gcmclient.config.Constants;
import com.happle.gcmclient.obj.ConversationObj;
import com.happle.gcmclient.obj.ConversationsNotSyncObj;
import com.happle.gcmclient.obj.GCMServerResponse;
import com.happle.gcmclient.obj.LngObj;
import com.happle.gcmclient.obj.MessageObj;
import com.happle.gcmclient.utility.ParameterUtil;

public final class BackendManager {

    private static final String DISPLAY_MESSAGE_ACTION = "BackendManager";
    private static final String MESSAGE = "MESSAGE";
    private static final int MAX_ATTEMPTS = 3;
    private static final int BACKOFF_MILLI_SECONDS = 2000;
    private static final Random random = new Random();
    private static final String username = "";
    private static final String user_pwd = "";

    public int sendMessage(MessageObj MsgObj, String senderID) {
        int error = Constants.FAILED;
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpConnectionParams
                .setConnectionTimeout(httpClient.getParams(), 10000); // Timeout
        // Limit
        HttpResponse response;
        JSONObject json = ParameterUtil.CreateSendMessageParamsJSON(senderID,
                username, user_pwd, MsgObj);

        // Making HTTP Request Constants.URL_SEND_MESSAGE
        try {
            HttpPost post = new HttpPost(Constants.URL_SEND_MESSAGE);
            StringEntity se = new StringEntity(json.toString(), HTTP.UTF_8);
            se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                    "application/json"));
            post.setHeader("Content-type", "application/json;charset=UTF-8");
            post.setEntity(se);

            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            String responseBody = httpClient.execute(post, responseHandler);
            JSONObject responseObj = new JSONObject(responseBody);
            GCMServerResponse resp = new GCMServerResponse();
            /* Checking response */
            if (responseBody != null) {
                resp.set_return_code(Integer.parseInt(responseObj
                        .getString("return_code")));
                resp.set_message(responseObj.getString("message"));
                error = resp.get_return_code();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return error;
    }

    public int sendLoginRegistration(String senderID, boolean isLogin) {
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        int error = Constants.FAILED;

        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost(isLogin ? Constants.URL_LOGIN
                : Constants.URL_REGISTER_CHANGESTATUS);
        JSONObject json = ParameterUtil.createChangeStatusParamsJSON(senderID,
                username, user_pwd, Constants.STATUS_ON);
        HttpResponse response;
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {
            Log.d(DISPLAY_MESSAGE_ACTION, "Attempt #" + i
                    + " to login register");
            try {
                StringEntity se = new StringEntity(json.toString());
                se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                        "application/json"));
                post.setEntity(se);
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String responseBody = httpClient.execute(post, responseHandler);
                JSONObject responseObj = new JSONObject(responseBody);
                GCMServerResponse resp = new GCMServerResponse();

				/* Checking response */
                if (responseBody != null) {
                    resp.set_return_code(Integer.parseInt(responseObj
                            .getString("return_code")));
                    resp.set_message(responseObj.getString("message"));
                    error = resp.get_return_code();
                    if (error == Constants.SUCCESS) {
                        i = MAX_ATTEMPTS;
                    }
                }
                // error = Integer.parseInt(res);
            } catch (Exception e) {
                Log.e(DISPLAY_MESSAGE_ACTION, "Failed to login on attempt " + i
                        + ":" + e);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(DISPLAY_MESSAGE_ACTION, "Sleeping for " + backoff
                            + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(DISPLAY_MESSAGE_ACTION,
                            "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return error;
                }
            }
            // increase backoff exponentially
            backoff *= 2;
        }
        return error;
    }

    public int sendUnregister(String senderID, boolean isLogout) {
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        int error = Constants.FAILED;

        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost(Constants.URL_UNREGISTER);
        JSONObject json = ParameterUtil.createUserDataParamsJSON(senderID,
                username, user_pwd);
        HttpResponse response;
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {

            Log.d(DISPLAY_MESSAGE_ACTION, "Attempt #" + i + " to unregister");
            try {
                StringEntity se = new StringEntity(json.toString());
                se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                        "application/json"));
                post.setEntity(se);
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String responseBody = httpClient.execute(post, responseHandler);
                JSONObject responseObj = new JSONObject(responseBody);
                GCMServerResponse resp = new GCMServerResponse();

				/* Checking response */
                if (responseBody != null) {
                    resp.set_return_code(Integer.parseInt(responseObj
                            .getString("return_code")));
                    resp.set_message(responseObj.getString("message"));
                    error = resp.get_return_code();
                }
            } catch (Exception e) {
                Log.e(DISPLAY_MESSAGE_ACTION, "Failed to register on attempt "
                        + i + ":" + e);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(DISPLAY_MESSAGE_ACTION, "Sleeping for " + backoff
                            + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(DISPLAY_MESSAGE_ACTION,
                            "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return error;
                }
            }
            if (error == Constants.SUCCESS) {
                i = MAX_ATTEMPTS;
            } else {
                // increase backoff exponentially
                backoff *= 2;
            }
        }
        return error;
    }

    public int sendChangeStatus(String senderID, int status) {
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        int error = Constants.FAILED;

        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost(Constants.URL_CHANGE_STATUS);
        JSONObject json = ParameterUtil.createChangeStatusParamsJSON(senderID,
                username, user_pwd, status);
        HttpResponse response;
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {

            Log.d(DISPLAY_MESSAGE_ACTION, "Attempt #" + i + " to change status");
            try {
                StringEntity se = new StringEntity(json.toString());
                se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                        "application/json"));
                post.setEntity(se);
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String responseBody = httpClient.execute(post, responseHandler);
                JSONObject responseObj = new JSONObject(responseBody);
                GCMServerResponse resp = new GCMServerResponse();

				/* Checking response */
                if (responseBody != null) {
                    resp.set_return_code(Integer.parseInt(responseObj
                            .getString("return_code")));
                    resp.set_message(responseObj.getString("message"));
                    error = resp.get_return_code();
                }
                // error = Integer.parseInt(res);
            } catch (Exception e) {
                Log.e(DISPLAY_MESSAGE_ACTION,
                        "Failed to change status on attempt " + i + ":" + e);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(DISPLAY_MESSAGE_ACTION, "Sleeping for " + backoff
                            + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(DISPLAY_MESSAGE_ACTION,
                            "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return error;
                }
            }
            if (error == Constants.SUCCESS) {
                i = MAX_ATTEMPTS;
            } else {
                // increase backoff exponentially
                backoff *= 2;
            }
        }
        return error;
    }

    void displayMessage(Context context, String message) {
        Intent intent = new Intent(DISPLAY_MESSAGE_ACTION);
        intent.putExtra(MESSAGE, message);
        context.sendBroadcast(intent);
    }

    public ArrayList<MessageObj> getMoreConversations(String regId,
                                                      int last_conversation_id, int more_conversation_number) {
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        int error = Constants.FAILED;
        ArrayList<MessageObj> downloadedConversations = new ArrayList<MessageObj>();
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost(Constants.URL_UPDATE_CONVERSATION);
        JSONObject json = ParameterUtil.CreateDownloadConversationParamsJSON(
                regId, last_conversation_id, more_conversation_number);
        HttpResponse response;
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {

            Log.d(DISPLAY_MESSAGE_ACTION, "Attempt #" + i + " to change status");
            try {
                StringEntity se = new StringEntity(json.toString());
                se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                        "application/json"));
                post.setEntity(se);
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String responseBody = httpClient.execute(post, responseHandler);
                JSONObject responseObj = new JSONObject(responseBody);

				/* Checking response */
                if (responseBody != null) {
                    // get messages array from responseObj
                    // downloadedConversations = responseObj
                    error = Constants.SUCCESS;
                }
            } catch (Exception e) {
                Log.e(DISPLAY_MESSAGE_ACTION,
                        "Failed to change status on attempt " + i + ":" + e);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(DISPLAY_MESSAGE_ACTION, "Sleeping for " + backoff
                            + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(DISPLAY_MESSAGE_ACTION,
                            "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return downloadedConversations;
                }
            }
            if (error == Constants.SUCCESS) {
                i = MAX_ATTEMPTS;
            } else {
                // increase backoff exponentially
                backoff *= 2;
            }
        }
        return downloadedConversations;
    }

    public int updateConversation(ConversationObj convObj, int conv_status, String registration_id) {
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        int error = Constants.FAILED;
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost(Constants.URL_UPDATE_CONVERSATION);
        JSONObject json = ParameterUtil.createUpdateConversationParamsJSON(convObj, conv_status, registration_id, username, user_pwd);
        HttpResponse response;
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {

            Log.d(DISPLAY_MESSAGE_ACTION, "Attempt #" + i + " to change status");
            try {
                StringEntity se = new StringEntity(json.toString());
                se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                        "application/json"));
                post.setEntity(se);
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String responseBody = httpClient.execute(post, responseHandler);
                JSONObject responseObj = new JSONObject(responseBody);
                GCMServerResponse resp = new GCMServerResponse();

		/* Checking response */
                if (responseBody != null) {
                    resp.set_return_code(Integer.parseInt(responseObj
                            .getString("return_code")));
                    resp.set_message(responseObj.getString("message"));
                    error = resp.get_return_code();
                }
            } catch (Exception e) {
                Log.e(DISPLAY_MESSAGE_ACTION, "Failed to change status on attempt "
                        + i + ":" + e);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(DISPLAY_MESSAGE_ACTION, "Sleeping for " + backoff
                            + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(DISPLAY_MESSAGE_ACTION,
                            "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return error;
                }
            }
            if (error == Constants.SUCCESS) {
                i = MAX_ATTEMPTS;
            } else {
                backoff *= 2;
            }
        }
        return error;
    }

    public int deleteConversation (ConversationObj convObj, String registration_id) {
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        int error = Constants.FAILED;
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost(Constants.URL_DELETE_CONVERSATION);
        JSONObject json = ParameterUtil.createDeleteConversationParamsJSON(convObj, registration_id, username, user_pwd);
        HttpResponse response;
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {

            Log.d(DISPLAY_MESSAGE_ACTION, "Attempt #" + i + " to change status");
            try {
                StringEntity se = new StringEntity(json.toString());
                se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                        "application/json"));
                post.setEntity(se);
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String responseBody = httpClient.execute(post, responseHandler);
                JSONObject responseObj = new JSONObject(responseBody);
                GCMServerResponse resp = new GCMServerResponse();

		/* Checking response */
                if (responseBody != null) {
                    resp.set_return_code(Integer.parseInt(responseObj
                            .getString("return_code")));
                    resp.set_message(responseObj.getString("message"));
                    error = resp.get_return_code();
                }
            } catch (Exception e) {
                Log.e(DISPLAY_MESSAGE_ACTION, "Failed to change status on attempt "
                        + i + ":" + e);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(DISPLAY_MESSAGE_ACTION, "Sleeping for " + backoff
                            + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(DISPLAY_MESSAGE_ACTION,
                            "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return error;
                }
            }
            if (error == Constants.SUCCESS) {
                i = MAX_ATTEMPTS;
            } else {
                backoff *= 2;
            }
        }
        return error;
    }

    public int updateLanguage(LngObj lngObj, String senderID) {
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        int error = Constants.FAILED;

        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost(Constants.URL_UPDATE_LANGUAGE);
        JSONObject json = ParameterUtil.CreateUpdateLanguageParamsJSON(lngObj,
                senderID, username, user_pwd);
        HttpResponse response;
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {

            Log.d(DISPLAY_MESSAGE_ACTION, "Attempt #" + i + " to change status");
            try {
                StringEntity se = new StringEntity(json.toString());
                se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                        "application/json"));
                post.setEntity(se);
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String responseBody = httpClient.execute(post, responseHandler);
                JSONObject responseObj = new JSONObject(responseBody);
                GCMServerResponse resp = new GCMServerResponse();

				/* Checking response */
                if (responseBody != null) {
                    resp.set_return_code(Integer.parseInt(responseObj
                            .getString("return_code")));
                    resp.set_message(responseObj.getString("message"));
                    error = resp.get_return_code();
                }
                // error = Integer.parseInt(res);
            } catch (Exception e) {
                Log.e(DISPLAY_MESSAGE_ACTION,
                        "Failed to change status on attempt " + i + ":" + e);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(DISPLAY_MESSAGE_ACTION, "Sleeping for " + backoff
                            + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(DISPLAY_MESSAGE_ACTION,
                            "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return error;
                }
            }
            if (error == Constants.SUCCESS) {
                i = MAX_ATTEMPTS;
            } else {
                // increase backoff exponentially
                backoff *= 2;
            }
        }
        error = Constants.SUCCESS; // temp, remove for prod
        return error;
    }

    public int syncData(Context mContext, ArrayList<LngObj> listLanguage,
                        ArrayList<MessageObj> listNewMsg,
                        ArrayList<ConversationsNotSyncObj> listUpdateMsg, String registration_id) {
        int error = Constants.FAILED;
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpConnectionParams
                .setConnectionTimeout(httpClient.getParams(), 10000); // Timeout
        // Limit
        HttpResponse response;
        JSONObject json = ParameterUtil.createSyncParamsJSON(mContext,
                listLanguage, listNewMsg, listUpdateMsg, registration_id,username, user_pwd);

        // Making HTTP Request Constants.URL_SEND_MESSAGE
        try {
            HttpPost post = new HttpPost(Constants.URL_SYNC_DATA);
            StringEntity se = new StringEntity(json.toString(), HTTP.UTF_8);
            se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
                    "application/json"));
            post.setHeader("Content-type", "application/json;charset=UTF-8");
            post.setEntity(se);

            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            String responseBody = httpClient.execute(post, responseHandler);
            Log.d("SyncResponse", "SyndData Response : " + responseBody);
            JSONObject responseObj = new JSONObject(responseBody);
            GCMServerResponse resp = new GCMServerResponse();
			/* Checking response */
            if (responseBody != null) {
                resp.set_return_code(Integer.parseInt(responseObj
                        .getString("return_code")));
                resp.set_message(responseObj.getString("message"));
                error = resp.get_return_code();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return error;
    }

}
